/**
 *	this file contains structures used in
 *	construct the three address code
 */

#ifndef	__COMPILER_PROJ2_DEF__
#define __COMPILER_PROJ2_DEF__

#ifndef __DEBUG__
#define __DEBUG__ 1
#endif

#include <string>
#include <map>
#include <vector>
#include <list>
#include <string>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

#define IS_JMP(op) ( op >=  OP_BGE && op <= OP_RET)
#define IS_CONJMP(op) ( op >=  OP_BGE && op <= OP_BNE)
#define IS_NUM(chr) (chr >= '0' && chr <= '9')

// the number larger then TYPE_STRUCT
enum __TYPE__ {
	TYPE_INT = 1,
	TYPE_ARRAY,
	TYPE_STRUCT,
	TYPE_PARAM,
	TYPE_TMPVAR
};

enum __OPCODEDEF__ {
	// data operation
	OP_ST = 1, //
	OP_ADD, //
	OP_SUB, //
	OP_MUL, //
	OP_DIV, //
	OP_MOD, //
	OP_SHL, //
	OP_SHR, //
	OP_BAND, //
	OP_BOR, //
	OP_BNOT, //
	OP_BXOR, //
	OP_PARA, //

	// jmp and branch
	OP_BGE = 1000, //
	OP_BGT, //
	OP_BLT, //
	OP_BLE, //
	OP_BEQ, //
	OP_BNE, //
	OP_JMP, //
	OP_CALL, //
	OP_RET   //
	// logical operation
	// these operation does not generate any code
	// OP_LAND = 2000,
	// OP_LOR,
	// OP_LNOT
};

/**
 *	addr is actually the names of variabls,
 *	it should be translated to adress in
 *	code generation phase;
 *	type, has no usage for now.May be deleted
 *	latter.
 *	for tmp vars generated by paser,names are
 *	tn for the nth var;
 */
struct symble{
	int type;
	int index; // dclearation index
	int size;
	string structname;
	std::vector<int> arrayIndex;
	vector<int>initval; // init value for global variables
};

struct symbleTableNode{
	map<string ,symble> v;
	map<string , map<string,int > > s; // STRUCT define
	map<string , vector<string> > sdef;// STRUCR define
	vector<string>	params; // reversed for future use;
	string name;
	int blockSize;
	int parent; // address for parent sybble table
	symbleTableNode(){
		blockSize = 0;
		parent = -1;
	}
};

struct threeAddCodeNode{
	int opcode;
	int env;
	string arg1;
	string arg2;
	string res;
	string lable; // lable for that code
};

/**
 *	structures used in yacc
 */
struct struct_VAR{
	string name;
	int type;
	std::vector<int> arrayIndex;
};

struct struct_STSPEC{
	map < string, int >m;
	int index;
};

struct struct_EXP{
	/**
	 * where the exp stored, can be a name inthe form
	 * like:
	 * "#%d" 		for tmp var;
	 * ID, 			variables
	 * ID[OFFSET] 	for arrays or struct element
	 * the integer valure is stored in offset tag.
	 * note that the last form ID[OFFSET] is not an
	 * array access, it is just how to calculate the
	 * address for that variable.OFFSET has unit of
	 * word, so it must mulpled by 4 to get the offset
	 * address in physical memory;
	*/
	string addr;
	//string offset;
	/**
	 *	trueList and falseList used for backpitching
	 */
	std::list<int> trueList;
	std::list<int> falseList;
	/**
	 *	true lable and false lable
	 */
	string trueLab;
	string falseLab;

	bool isBoolExp;
	bool isConst;
	int val;
	struct_EXP(){
		isBoolExp = false;
		isConst = false;
	}
};
/**
 *	global variables
 */

extern vector <symbleTableNode> symbleTable;


/*********************************************
 *	Three address code
 ********************************************/
int  findVar(int env , string name);
int  findSymble(int env , string name);
int  findStruct(int env , string name);
void addVar(int env, const struct_VAR * var);
void addParams(int env,vector<string> *params);
void addStruct(
	int env,
	string *name,
	vector<string> *sstruct);
void addStructVar(int env,string sname,vector<string>*vars);
void addInitVal(struct_VAR * var,std::vector<struct struct_EXP *> * exps);

string newTemp(void);
string newLable(void);
int newENV(void);
int genCode(int opcode,
	string arg1,
	string arg2 ,
	string res );
int    getStructElementIndex(int env,const string *var,const string *ele);
void   genLable(const string &lable);
string genLable(void);
string genCodeForExp(struct_EXP *addr1, struct_EXP *addr2,int op);
string genCodeForExp(struct_EXP *addr1, string addr2,int op);
string genCodeForExp(string addr1, struct_EXP *addr2,int op);
string genCodeForExp(string addr1, string addr2,int op);
string genCodeForAssign(string src, const string &dst);
void   genCodeForInit(
	int env,
	string name,
	std::vector<struct struct_EXP *>* init);
int genCodeForCall(
	string name,
	std::vector<struct struct_EXP *>* arg
	);

void backPatch(std::list<int> &l, string lable);

void bool2int(struct struct_EXP *);
void int2bool(struct struct_EXP * &);

void sysInit(void);

string i2s(int val);
string op2s(int opcode);

void recErr(string);
void printErr(void);
void writeIRtofile(const char * name);

// decode varname
int scanEnv(string varname);
string scanOffset(string varname);
string scanName(string varname);

#if __DEBUG__
	void printIntermediateCode(void);
	void printVar(void);
	void printStruct(void);
	void printSymbleTable(void);
#endif /* __DEBUG__ */



#endif /* __COMPILER_PROJ2_DEF__ */
